<template>
    <!-- 操作按钮 -->
    <div class="flex flex-wrap gap-2 ml-2 mb-2">
        <!-- 返回 -->
        <el-button @click="backCustomerList" :icon="Back">返回</el-button>

        <!-- 总数量 -->
        <el-text tag="b">产品总数：{{ data.length }}</el-text>

        <!-- 分隔符 -->
        <el-divider direction="vertical" style="height: 32px" />

        <!-- 搜索框+按钮 -->
        <el-input
            style="width: 180px"
            v-model="searchProductValue"
            placeholder="请输入产品关键字查询"
            clearable
            @keydown.enter="searchProductEvent"
            @clear="inputClearEvent"
        />
        <el-button @click="searchProductEvent" :icon="Search">搜索</el-button>

        <!-- 选项组 -->
        <el-button-group>
            <!-- 常驻 -->
            <!-- 刷新 -->
            <el-button type="primary" :icon="Refresh" @click="updateForm()">刷新</el-button>
            <el-button type="primary" :icon="Printer" @click="printProduction">生产单</el-button>
            <el-button type="primary" :icon="Printer" @click="printProductSymbol">产品标签</el-button>
            <!-- 添加 -->
            <el-button v-if="checkPermi(['product:create'])" type="primary" :icon="Plus" @click="addProductVisible = true">添加</el-button>

            <!-- 正面 -->
            <!-- 删除 -->
            <el-popconfirm
                v-if="checkPermi(['product:update']) && state"
                title="删除后的产品，将会被暂存到回收站中。"
                width="200"
                @confirm="deleteProductEvent"
            >
                <template #reference>
                    <el-button type="primary" :icon="Delete">删除</el-button>
                </template>
            </el-popconfirm>
            <!-- 回收站 -->
            <el-button v-if="state" :icon="DeleteFilled" type="primary" @click="changeProductList(false)">回收站</el-button>
            <el-button v-if="checkPermi(['product:update']) && state" type="primary" @click="reorderProductPriorityEvent">产品排序</el-button>

            <!-- 背面 -->
            <!-- 恢复数据 -->
            <el-button v-if="checkPermi(['product:update']) && !state" type="primary" :icon="MagicStick" @click="recoverProductEvent">恢复</el-button>
            <!-- 产品列表 -->
            <el-button v-if="!state" :icon="List" type="primary" @click="changeProductList(true)">产品列表</el-button>
            <!-- 彻底删除 -->
            <el-popconfirm
                v-if="checkPermi(['product:delete']) && !state"
                title="彻底删除后将无法找回，谨慎操作！"
                width="200"
                @confirm="deleteProductCompletelyEvent"
            >
                <template #reference>
                    <el-button :icon="Delete" type="primary"> 彻底删除 </el-button>
                </template>
            </el-popconfirm>
        </el-button-group>

        <!-- 多种方式导入 -->
        <el-dropdown v-if="checkPermi(['product:import/export'])">
            <span class="el-dropdown-link">
                <el-button type="primary" :icon="ArrowDown">导入</el-button>
            </span>
            <template #dropdown>
                <el-dropdown-menu>
                    <!-- json文件导入 -->
                    <el-dropdown-item>
                        <el-upload
                            ref="upload"
                            :auto-upload="false"
                            :show-file-list="false"
                            @change="handleFileChange"
                            :limit="1"
                            :on-exceed="handleExceed"
                            accept=".json"
                        >
                            <el-button type="primary" :icon="TableImport">.json文件导入</el-button>
                        </el-upload>
                    </el-dropdown-item>
                    <!-- xlsx模板导入 -->
                    <el-dropdown-item>
                        <el-upload
                            ref="upload"
                            :auto-upload="false"
                            :show-file-list="false"
                            @change="handleFileChange"
                            :limit="1"
                            :on-exceed="handleExceed"
                            accept=".xlsx"
                        >
                            <el-button type="primary" :icon="Template">.xlsx模板导入</el-button>
                        </el-upload>
                    </el-dropdown-item>
                    <!-- 下载xlsx模板 -->
                    <el-dropdown-item>
                        <el-button type="primary" :icon="Download" @click="downloadProductTemplateEvent">下载.xlsx模板</el-button>
                    </el-dropdown-item>
                </el-dropdown-menu>
            </template>
        </el-dropdown>

        <!-- 多种方式导出 -->
        <el-dropdown v-if="checkPermi(['product:import/export'])">
            <span class="el-dropdown-link">
                <el-button type="primary" :icon="ArrowDown">导出</el-button>
            </span>
            <template #dropdown>
                <el-dropdown-menu>
                    <!-- json格式文件导出 -->
                    <el-dropdown-item>
                        <el-button type="primary" :icon="TableExport" @click="exportProductJsonEvent">.json格式导出</el-button>
                    </el-dropdown-item>
                    <!-- xlsx格式文件导出 -->
                    <el-dropdown-item>
                        <el-button type="primary" :icon="Template" @click="exportProductXlsxEvent">.xlsx格式导出</el-button>
                    </el-dropdown-item>
                </el-dropdown-menu>
            </template>
        </el-dropdown>
    </div>

    <!-- 表格展示 -->
    <div style="height: calc(100vh - 140px); width: 100%; overflow: auto">
        <el-auto-resizer>
            <template #default="{ height, width }">
                <FTableV2
                    v-model="selected"
                    :data="data"
                    :width="width"
                    :height="height"
                    :row-height="rowHeight"
                    :other-column="otherColumn"
                    @update-data="updateData"
                ></FTableV2>
            </template>
        </el-auto-resizer>
    </div>

    <!-- 打印产品生产单 -->
    <PrintProductionNoOrder
        v-model:print-visible="printVisible"
        v-model:print-data="printData"
        :customer-name="customerInfo.customerName"
    ></PrintProductionNoOrder>

    <!-- 打印产品符号 -->
    <PrintProductSymbol v-model:print-product-symbol-visible="printProductSymbolVisible" v-model:print-product-symbol-data="printProductSymbolData" />

    <!-- 添加产品表单Dialog -->
    <el-dialog v-model="addProductVisible" width="80%" draggable :show-close="false" :close-on-click-modal="false">
        <!-- 自定义标题 -->
        <template #header="{ close, titleId, titleClass }">
            <!-- 自定义标题内容 -->
            <div class="dialog-header">
                <!-- 标题文字 -->
                <h4 :id="titleId" :class="titleClass">添加产品<el-text type="warning" size="large"> --- ESC关闭</el-text></h4>
                <!-- 关闭按钮 -->
                <el-button type="danger" @click="close">
                    <el-icon class="el-icon--left">
                        <CircleCloseFilled />
                    </el-icon>
                    关闭
                </el-button>
            </div>
        </template>
        <el-form ref="productFormRef" :rules="rules" :model="addProductForm" label-width="130px">
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="包装类型：" required prop="boxType">
                    <el-select v-model="addProductForm.boxType" placeholder="请选择类型">
                        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" :disabled="item.disabled" />
                    </el-select>
                </el-form-item>
                <el-form-item v-if="addProductForm.boxType == '包装箱'" class="w-1/2 flex" label="外箱速算：">
                    <div class="inline-block mr-2">
                        <el-text type="primary">粘口(mm)：</el-text>
                        <el-input type="number" v-model="glueSize" style="width: 60px" @change="changeGlueSizeEvent" />
                    </div>
                    <el-button @click="calculateThreeLayersOuterBoxSize">三层箱算规格</el-button>
                    <el-button @click="calculateFiveLayersOuterBoxSize">五层箱算规格</el-button>
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="产品名称：" required prop="productName">
                    <el-input v-model="addProductForm.productName" clearable />
                </el-form-item>
                <el-form-item class="w-1/2" label="产品物料号：" prop="materialNumber">
                    <el-input v-model="addProductForm.materialNumber" clearable />
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="产品尺寸(mm)：" prop="productSize">
                    <el-input v-model="addProductForm.productSize" clearable placeholder="请输入尺寸，示例：333*222(*111)" />
                </el-form-item>
                <el-form-item class="w-1/2" label="产品规格：" prop="productSpecification">
                    <el-input v-model="addProductForm.productSpecification" clearable />
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="面纸规格(mm)：" prop="tissueSize">
                    <el-input v-model="addProductForm.tissueSize" clearable placeholder="请输入规格，示例：1234*123" />
                </el-form-item>
                <el-form-item class="w-1/2" label="瓦楞规格(mm)：" prop="corrugatedSize">
                    <el-input v-model="addProductForm.corrugatedSize" clearable placeholder="请输入规格，示例：1234*123" />
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="材质：" required prop="materialQuality">
                    <el-input v-model="addProductForm.materialQuality" clearable />
                </el-form-item>
                <el-form-item class="w-1/2" label="压线：" prop="crimping">
                    <el-input v-model="addProductForm.crimping" clearable />
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="拼数：" required prop="spell">
                    <el-input type="number" v-model="addProductForm.spell" />
                </el-form-item>
                <el-form-item class="w-1/2" label="工艺：" required prop="process">
                    <el-input v-model="addProductForm.process" clearable />
                </el-form-item>
            </div>
            <div class="flex w-full gap-2">
                <el-form-item class="w-1/2" label="不含税价格：" required prop="excludTaxPrice">
                    <el-input v-model="addProductForm.excludTaxPrice" @blur="blurPriceEvent('excludTaxPrice')" />
                </el-form-item>
                <el-form-item class="w-1/2" label="含税价格：" required prop="includeTaxPrice">
                    <el-input v-model="addProductForm.includeTaxPrice" @blur="blurPriceEvent('includeTaxPrice')" />
                </el-form-item>
            </div>
            <el-form-item class="w-full" label="产品描述：" prop="description">
                <el-input type="textarea" v-model="addProductForm.description" />
            </el-form-item>
        </el-form>
        <template #footer>
            <div class="dialog-footer">
                <el-button type="warning" plain @click="resetAddProductFormEvent"> 重置 </el-button>
                <el-button type="primary" plain @click="addProductSubmitEvent"> 提交 </el-button>
            </div>
        </template>
    </el-dialog>

    <!-- 上传产品图稿的Dialog -->
    <el-dialog v-model="uploadProductThumbnailDialogVisible" draggable width="60%" :show-close="false">
        <!-- 自定义标题 -->
        <template #header="{ close, titleId, titleClass }">
            <!-- 自定义标题内容 -->
            <div class="dialog-header">
                <!-- 标题文字 -->
                <h4 :id="titleId" :class="titleClass">上传产品缩略图<el-text type="warning" size="large"> --- ESC关闭</el-text></h4>
                <!-- 关闭按钮 -->
                <el-button type="danger" @click="close">
                    <el-icon class="el-icon--left">
                        <CircleCloseFilled />
                    </el-icon>
                    关闭
                </el-button>
            </div>
        </template>
        <!-- 自定义内容 -->
        <el-upload
            ref="uploadProductThumbnailRef"
            drag
            with-credentials
            accept=".jpg,.png,.webp,.jpeg"
            list-type="picture"
            :data="{
                ...customerInfo,
                productName: uploadProductThumbnailName,
                productId: uploadProductThumbnailId,
                thumbnail: true,
                creator: useUserStore().username,
                creatorId: useUserStore().id,
            }"
            :action="thumbnailAction"
            :limit="1"
            :auto-upload="false"
            :on-change="handleProductThumbnailChangeEvent"
            :on-exceed="handleProductThumbnailExceedEvent"
            :on-progress="uploadProductThumbnailProgressEvent"
            :on-success="uploadProductThumbnailSuccessEvent"
            :on-error="uploadProductThumbnailErrorEvent"
        >
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">拖拽到此处 或者 <em>点击上传</em></div>
            <template #tip>
                <div class="el-upload__tip">小于2mb的jpg/png/webp的文件且宽高比大于1</div>
            </template>
        </el-upload>
        <!-- 显示正确/错误的图片尺寸 -->
        <el-text :type="imageSize.width >= imageSize.height ? 'success' : 'danger'" tag="b">
            图片尺寸: {{ imageSize.width }} x {{ imageSize.height }}
        </el-text>
        <el-text :type="imageSize.width >= imageSize.height ? 'success' : 'danger'" tag="b">
            {{ imageSize.width >= imageSize.height ? '✅' : '❌' }}
        </el-text>
        <img v-show="false" :src="imageSizeSrc" alt="calculateImageSize" @load="onImageLoad" />
        <!-- 底部 -->
        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" plain @click="productThumbnailSubmitEvent"> 提交 </el-button>
            </div>
        </template>
    </el-dialog>

    <!-- 查看产品图稿的Dialog -->
    <el-dialog v-model="showProductDesignDialogVisible" draggable fullscreen :show-close="false">
        <!-- 自定义标题 -->
        <template #header="{ close, titleId, titleClass }">
            <!-- 自定义标题内容 -->
            <div class="dialog-header">
                <!-- 标题文字 -->
                <h4 :id="titleId" :class="titleClass">查看产品印刷图稿<el-text type="warning" size="large"> --- ESC关闭</el-text></h4>
                <!-- 关闭按钮 -->
                <el-button type="danger" @click="close">
                    <el-icon class="el-icon--left">
                        <CircleCloseFilled />
                    </el-icon>
                    关闭
                </el-button>
            </div>
        </template>
        <!-- 自定义内容 -->
        <el-descriptions title="产品图稿" border>
            <div v-for="(item, index) in data.find((item) => item._id == showProductDesignId)?.design" :key="index">
                <!-- 缩略图 -->
                <el-descriptions-item>
                    <template #label>
                        <div class="flex items-center gap-2">
                            <el-icon>
                                <PictureInPicture16Regular />
                            </el-icon>
                            缩略图文件名称
                        </div>
                    </template>
                    {{ item.thumbnail == '' ? '/' : item.thumbnail.split('/')[`${item.thumbnail.split('/').length - 1}`] }}
                </el-descriptions-item>
                <!-- 印刷原稿 -->
                <el-descriptions-item>
                    <template #label>
                        <div class="flex items-center gap-2">
                            <el-icon>
                                <HandDraw24Regular />
                            </el-icon>
                            印刷原稿
                        </div>
                    </template>
                    {{ item.designFile == '' ? '/' : item.designFile.split('/')[`${item.designFile.split('/').length - 1}`] }}
                </el-descriptions-item>
                <!-- 版本工具 -->
                <el-descriptions-item>
                    <template #label>
                        <div class="flex items-center gap-2">
                            <el-icon>
                                <Tools />
                            </el-icon>
                            版本工具
                        </div>
                    </template>
                    <div class="flex gap-2">
                        <el-upload
                            ref="uploadProductDesignRef"
                            name="design"
                            :action="designAction"
                            with-credentials
                            :data="{
                                ...customerInfo,
                                productName: showProductDesignName,
                                productId: showProductDesignId,
                                thumbnail: false,
                                index: index,
                                creator: useUserStore().username,
                                creatorId: useUserStore().id,
                            }"
                            :limit="1"
                            :on-exceed="handleProductDesignExceedEvent"
                            :on-progress="uploadProductDesignProgressEvent"
                            :on-success="uploadProductDesignSuccessEvent"
                            :on-error="uploadProductDesignErrorEvent"
                        >
                            <el-button type="primary" :icon="CloudUpload">上传原稿</el-button>
                        </el-upload>
                        <el-button type="primary" :icon="CloudDownload" @click="downloadProductDesignEvent(item.designFile)"> 下载原稿 </el-button>
                        <el-dropdown>
                            <span class="el-dropdown-link">
                                <el-button type="primary" @click="" :icon="ArrowDown">删除</el-button>
                            </span>
                            <template #dropdown>
                                <el-dropdown-menu>
                                    <el-dropdown-item :icon="DeleteArrowBack20Regular" @click="deleteProductDesignEvent('thumbnail', index)">
                                        删除缩略图
                                    </el-dropdown-item>
                                    <el-dropdown-item :icon="DeleteDismiss20Regular" @click="deleteProductDesignEvent('designFile', index)">
                                        删除源文件
                                    </el-dropdown-item>
                                    <el-dropdown-item :icon="DeleteOff20Regular" @click="deleteProductDesignEvent('all', index)">
                                        删除全部
                                    </el-dropdown-item>
                                </el-dropdown-menu>
                            </template>
                        </el-dropdown>
                    </div>
                </el-descriptions-item>
            </div>
        </el-descriptions>
    </el-dialog>
</template>

<script setup lang="tsx">
import { Back, Plus, Search, Refresh, Printer, DeleteFilled, List, MagicStick } from '@element-plus/icons-vue';
import { CircleCloseFilled, ArrowDown, Download, Delete, UploadFilled } from '@element-plus/icons-vue';
import { TableImport, Template, TableExport, Tools, CloudUpload, CloudDownload } from '@vicons/tabler';
import { PictureInPicture16Regular, HandDraw24Regular, DeleteArrowBack20Regular, DeleteDismiss20Regular, DeleteOff20Regular } from '@vicons/fluent';
import { checkPermi, checkRole } from '@utils/permission';
import { Column, ElInput, FormRules, genFileId, ElButton, ElImage, ElTooltip } from 'element-plus';
import { UploadFile, UploadFiles, UploadInstance, UploadProps, UploadRawFile, ElUpload, UploadProgressEvent } from 'element-plus';
import { getProductList, checkProductName, createProduct, deleteProductDesign, updateProduct } from '@api/product';
import { importProduct, deleteProduct, deleteProductCompletely, recoverProduct, reorderProductPriority } from '@api/product';
import { useUserStore } from '@/store/modules/user';
import { read, utils, writeFile } from 'xlsx';
import dayjs from 'dayjs';
import { HttpUrl } from '@api/httpUrl';
import { downloadProductTemplate, downloadProductDesign } from '@/api/download';
import { FunctionalComponent } from 'vue';
import { useDictionaryStore } from '@/store/modules/dictionary';
import Decimal from 'decimal.js';
import { bytesToMB } from '@utils/calculate';
import pictureError from '@/assets/img/common/pictureError.png';
import PrintProductionNoOrder from './PrintProductionNoOrder.vue';

onMounted(() => {
    generateDisableColumn();
    updateForm();
});

/* ******************************通用属性/方法****************************** */
// 字典数据
const useDictionary = useDictionaryStore();
// 产品信息
const customerInfo = defineModel<{
    customerId: string;
    customerName: string;
    customerAbbreviation: string;
}>({ required: true });
// 勾选的表格数据
const selected = reactive<string[]>([]);
// 产品是否激活
const state = ref(true);
// 当前服务器主机名和端口
const httpUrl = import.meta.env.VITE_APP_SERVER_URL;
// 更新表格的方法
const updateForm = (message: string = '查询激活产品成功') => {
    // 获取产品列表
    getProductList(customerInfo.value.customerId).then((res) => {
        // 清空表格数据
        dataCache.splice(0);
        selected.splice(0);
        data.length = 0;
        res.data.forEach((item: any, index: number) => {
            // 筛选可用的产品
            if (item.productAvailable == state.value) {
                item.checked = false;
                item.order = index + 1;
                item.editing = false;
                data.push(item);
                dataCache.push(item);
            }
        });
        ElMessage({
            message,
            type: 'success',
            grouping: true,
        });
    });
};
// 更新数据的方法
const updateData = (id: string, field: Column['dataKey'], value: string | boolean | number | any[]) => {
    if (checkPermi(['product:update'])) {
        updateProduct(customerInfo.value.customerId, customerInfo.value.customerName, { id, field, value }).then(() => {
            updateForm('更新产品信息成功');
        });
    }
};

/* ******************************组件el-table-v2 表格属性****************************** */
// 表格数据缓存
const dataCache: AjaxResponse['productList'] = [];
// 表格数据
const data = reactive<AjaxResponse['productList']>([]);
// inputNumber函数式组件
type InputNumberCessProps = {
    value: string;
    // 在 Input 值改变时触发
    onInput: (value: string) => void;
    // 当选择器的输入框获得焦点时触发
    onFocus: () => void;
    // 当选择器的输入框失去焦点时触发
    onBlur: () => void;
};
const InputNumberCell: FunctionalComponent<InputNumberCessProps> = ({ value, onFocus, onBlur, onInput }) => {
    return <ElInput modelValue={value} type={'number'} onFocus={onFocus} onBlur={onBlur} onInput={onInput} />;
};
// input函数式组件
type InputCessProps = {
    value: string;
    // 在 Input 值改变时触发
    onInput: (value: string) => void;
    // 当选择器的输入框获得焦点时触发
    onFocus: () => void;
    // 当选择器的输入框失去焦点时触发
    onBlur: () => void;
};
const InputCell: FunctionalComponent<InputCessProps> = ({ value, onFocus, onBlur, onInput }) => {
    return <ElInput modelValue={value} type={'text'} onFocus={onFocus} onBlur={onBlur} onInput={onInput} />;
};
// image函数式组件
type ImageCessProps = {
    src: string;
    loading: 'lazy';
    previewSrcList: string[];
};
const ImageCell: FunctionalComponent<ImageCessProps> = ({ src, loading, previewSrcList }) => {
    return <ElImage src={src} loading={loading} previewSrcList={previewSrcList} previewTeleported></ElImage>;
};
// tooltip函数式组件
type TooltipCessProps = {
    rowData: any;
    column: any;
    content: string;
    onEnterEditMode: (e: any) => void;
};
const TooltipCell: FunctionalComponent<TooltipCessProps> = ({ rowData, column, content, onEnterEditMode }) => {
    return (
        <ElTooltip content={content} placement="right">
            <div
                class={rowData[column.dataKey!] === '' ? 'table-v2-inline-editing-trigger-trim text' : 'table-v2-inline-editing-trigger text'}
                onClick={onEnterEditMode}
            >
                {rowData[column.dataKey!]}
            </div>
        </ElTooltip>
    );
};

// 禁用的列
const disable = reactive<string[]>([]);
// 输入框的原始值
let inputOriginValue = 0;
// 表格独有的column
const otherColumn = reactive<{ [key: string]: Column<any> }>({
    priority: {
        key: 'priority',
        dataKey: 'priority',
        width: 60,
        align: 'center',
        title: '编号',
        cellRenderer: ({ rowData, column }) => {
            // 输入框编辑模式
            const onEnterEditMode = () => {
                rowData.editing = true;
                inputOriginValue = rowData[column.dataKey!];
            };

            // 输入框内容改变时触发
            const onInput = (value: string) => {
                rowData[column.dataKey!] = value;
            };

            // 输入框退出编辑模式 -- 更新到服务器
            const onExitEditMode = () => {
                // 输入框退出编辑模式
                rowData.editing = false;
                // 对比新旧值
                if (Number(rowData[column.dataKey!]) !== Number(inputOriginValue)) {
                    // 更新到服务器
                    updateData(rowData._id, column.dataKey!, rowData[column.dataKey!]);
                }
            };

            // 判断是否为文本类型
            return rowData.editing ? (
                <InputCell value={rowData[column.dataKey!]} onFocus={onEnterEditMode} onBlur={onExitEditMode} onInput={onInput} />
            ) : (
                <div class={'table-v2-inline-editing-trigger'} onClick={onEnterEditMode}>
                    {rowData[column.dataKey!]}
                </div>
            );
        },
    },
    productName: {
        key: 'productName',
        dataKey: 'productName',
        width: 200,
        align: 'center',
        title: '产品名称',
        cellRenderer: ({ rowData, column }) => {
            // 输入框编辑模式
            const onEnterEditMode = () => {
                rowData.editing = true;
                inputOriginValue = rowData[column.dataKey!];
            };

            // 输入框内容改变时触发
            const onInput = (value: string) => {
                // 去除特殊字符/和\
                const reg1 = new RegExp(/\\/, 'ig');
                const reg2 = new RegExp('/', 'ig');
                rowData[column.dataKey!] = value.replace(reg1, '').replace(reg2, '');
            };

            // 输入框退出编辑模式 -- 更新到服务器
            const onExitEditMode = () => {
                // 输入框退出编辑模式
                rowData.editing = false;
                // 对比新旧值
                if (rowData[column.dataKey!] !== inputOriginValue) {
                    // 更新到服务器
                    updateData(rowData._id, column.dataKey!, rowData[column.dataKey!]);
                }
            };

            return rowData.editing ? (
                <InputCell value={rowData[column.dataKey!]} onFocus={onEnterEditMode} onBlur={onExitEditMode} onInput={onInput} />
            ) : (
                <div
                    class={rowData[column.dataKey!] === '' ? 'table-v2-inline-editing-trigger-trim text' : 'table-v2-inline-editing-trigger text'}
                    onClick={onEnterEditMode}
                >
                    {rowData[column.dataKey!]}
                </div>
            );
        },
    },
    productSize: {
        key: 'productSize',
        dataKey: 'productSize',
        width: 120,
        align: 'center',
        title: '产品尺寸',
        cellRenderer: ({ rowData, column }) => {
            // 输入框编辑模式
            const onEnterEditMode = () => {
                rowData.editing = true;
                inputOriginValue = rowData[column.dataKey!];
            };

            // 输入框内容改变时触发
            const onInput = (value: string) => {
                rowData[column.dataKey!] = value;
            };

            // 输入框退出编辑模式 -- 更新到服务器
            const onExitEditMode = () => {
                // 输入框退出编辑模式
                rowData.editing = false;

                if (rowData[column.dataKey!] === '') {
                    // 更新到服务器
                    updateData(rowData._id, column.dataKey!, rowData[column.dataKey!]);
                    return;
                }

                // 对比新旧值
                if (rowData[column.dataKey!] !== inputOriginValue) {
                    // 产品尺寸检验
                    const productSizeReg1 = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}[*][0-9]{0,4}$/);
                    const productSizeReg2 = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}$/);
                    if (!productSizeReg1.test(rowData[column.dataKey!]) && !productSizeReg2.test(rowData[column.dataKey!])) {
                        ElMessage.error('产品尺寸格式错误');
                        // 返回原数据
                        rowData[column.dataKey!] = inputOriginValue;
                        return;
                    }

                    // 更新到服务器
                    updateData(rowData._id, column.dataKey!, rowData[column.dataKey!]);
                }
            };

            // 计算content内容
            let content = '';

            // 计算面纸
            const tissueArea = rowData.tissueSize
                ? (Number(rowData.tissueSize.split('*')[0]) * Number(rowData.tissueSize.split('*')[1]) * 0.000001).toFixed(2)
                : '0';
            content += `面纸尺寸：${tissueArea} m² | `;

            // 计算瓦纸
            const corrugatedArea = rowData.corrugatedSize
                ? (Number(rowData.corrugatedSize.split('*')[0]) * Number(rowData.corrugatedSize.split('*')[1]) * 0.000001).toFixed(2)
                : '0';
            content += `瓦纸尺寸：${corrugatedArea} m²`;

            // 含税价验证
            if (isFinite(rowData.includeTaxPrice) && Number(rowData.includeTaxPrice) !== 0) {
                // 面纸验证
                if (Number(tissueArea) !== 0) {
                    content += ` | 面纸含税平方价：${(rowData.includeTaxPrice / Number(tissueArea)).toFixed(2)} 元/m² |`;
                }
                // 瓦纸验证
                if (Number(corrugatedArea) !== 0) {
                    content += ` | 瓦纸含税平方价：${(rowData.includeTaxPrice / Number(corrugatedArea)).toFixed(2)} 元/m²`;
                }
            }

            // 不含税价验证
            if (isFinite(rowData.excludTaxPrice) && Number(rowData.excludTaxPrice) !== 0) {
                // 面纸验证
                if (Number(tissueArea) !== 0) {
                    content += ` | 面纸不含税平方价：${(rowData.excludTaxPrice / Number(tissueArea)).toFixed(2)} 元/m² |`;
                }
                // 瓦纸验证
                if (Number(corrugatedArea) !== 0) {
                    content += ` | 瓦纸不含税平方价：${(rowData.excludTaxPrice / Number(corrugatedArea)).toFixed(2)} 元/m²`;
                }
            }

            return rowData.editing ? (
                <InputCell value={rowData[column.dataKey!]} onFocus={onEnterEditMode} onBlur={onExitEditMode} onInput={onInput} />
            ) : (
                <TooltipCell rowData={rowData} column={column} content={content} onEnterEditMode={onEnterEditMode}></TooltipCell>
            );
        },
    },
    design: {
        key: 'design',
        dataKey: 'design',
        width: 160,
        align: 'center',
        title: '设计图',
        cellRenderer: ({ rowData }) => {
            // 打开上传dialog
            const openUploadThumbnailDialog = () => {
                uploadProductThumbnailDialogVisible.value = true;
                uploadProductThumbnailName.value = rowData['productName'];
                uploadProductThumbnailId.value = rowData['_id'];
            };

            // 查看图稿的dialog
            const showProductDesignDialog = () => {
                showProductDesignDialogVisible.value = true;
                showProductDesignName.value = rowData['productName'];
                showProductDesignId.value = rowData['_id'];
            };

            const previewSrcList = rowData.design.map((item: any) => httpUrl + item.thumbnail);

            return rowData.design.length > 0 ? (
                <div class={'flex items-center'}>
                    <div class={'flex flex-wrap justify-center items-center mr-1 gap-1'}>
                        <ElButton class={'sfc-el-button'} size={'small'} onClick={openUploadThumbnailDialog}>
                            上传
                        </ElButton>
                        <ElButton class={'sfc-el-button'} size={'small'} onClick={showProductDesignDialog}>
                            查看
                        </ElButton>
                    </div>
                    <ImageCell
                        src={rowData.design[0].thumbnail == '' ? pictureError : `${httpUrl}` + rowData.design[0].thumbnail}
                        loading={'lazy'}
                        previewSrcList={previewSrcList}
                    />
                </div>
            ) : (
                <ElButton size={'small'} onClick={openUploadThumbnailDialog}>
                    上传
                </ElButton>
            );
        },
    },
    // 同步更正含税/不含税
    excludTaxPrice: {
        key: 'excludTaxPrice',
        dataKey: 'excludTaxPrice',
        width: 120,
        align: 'center',
        title: '不含税价格',
        cellRenderer: ({ rowData, column }) => {
            // 输入框编辑模式
            const onEnterEditMode = () => {
                rowData.editing = true;
                inputOriginValue = rowData[column.dataKey!];
            };

            // 输入框内容改变时触发
            const onInput = (value: string) => {
                rowData[column.dataKey!] = value;
            };

            // 输入框退出编辑模式 -- 更新到服务器
            const onExitEditMode = () => {
                // 输入框退出编辑模式
                rowData.editing = false;
                // 对比新旧值
                if (Number(rowData[column.dataKey!]) !== Number(inputOriginValue)) {
                    // 不含税价格/含税价格 更新到服务器
                    updateData(rowData._id, column.dataKey!, Number(rowData[column.dataKey!]));
                    updateData(rowData._id, 'includeTaxPrice', Number(Decimal.mul(Number(rowData[column.dataKey!]), 1.13).toFixed(2)));
                }
            };
            return rowData.editing ? (
                <InputNumberCell value={rowData[column.dataKey!]} onFocus={onEnterEditMode} onBlur={onExitEditMode} onInput={onInput} />
            ) : (
                <div class={'table-v2-inline-editing-trigger'} onClick={onEnterEditMode}>
                    {rowData[column.dataKey!]}
                </div>
            );
        },
    },
    // 同步更正含税/不含税
    includeTaxPrice: {
        key: 'includeTaxPrice',
        dataKey: 'includeTaxPrice',
        width: 120,
        align: 'center',
        title: '含税价格',
        cellRenderer: ({ rowData, column }) => {
            // 输入框编辑模式
            const onEnterEditMode = () => {
                rowData.editing = true;
                inputOriginValue = rowData[column.dataKey!];
            };

            // 输入框内容改变时触发
            const onInput = (value: string) => {
                rowData[column.dataKey!] = value;
            };

            // 输入框退出编辑模式 -- 更新到服务器
            const onExitEditMode = () => {
                // 输入框退出编辑模式
                rowData.editing = false;
                // 对比新旧值
                if (Number(rowData[column.dataKey!]) !== Number(inputOriginValue)) {
                    // 更新到服务器
                    updateData(rowData._id, column.dataKey!, Number(rowData[column.dataKey!]));
                    updateData(rowData._id, 'excludTaxPrice', Number(Decimal.div(Number(rowData[column.dataKey!]), 1.13).toFixed(2)));
                }
            };

            return rowData.editing ? (
                <InputNumberCell value={rowData[column.dataKey!]} onFocus={onEnterEditMode} onBlur={onExitEditMode} onInput={onInput} />
            ) : (
                <div class={'table-v2-inline-editing-trigger'} onClick={onEnterEditMode}>
                    {rowData[column.dataKey!]}
                </div>
            );
        },
    },
});
// 生成禁用列 -- 根据字典提供的权限加工otherColumn对象生成禁用列表
const generateDisableColumn = () => {
    // 遍历所有字段
    for (const key in otherColumn) {
        if (Object.prototype.hasOwnProperty.call(otherColumn, key)) {
            // 获取key在字典中的数据
            const { definition, roles } = useDictionary.getDictionaryUseField(key);
            // 判断是否为空
            if (definition == '') {
                disable.push(key);
                continue;
            }
            // 判断当前用户是否有权限查看该字段
            if (!checkRole(roles)) {
                disable.push(key);
            }
        }
    }
};
// 行高
const rowHeight = ref(60);

/* ******************************返回产品列表属性/方法****************************** */
// 返回产品列表
const backCustomerList = () => {
    customerInfo.value.customerId = '';
    customerInfo.value.customerName = '';
    customerInfo.value.customerAbbreviation = '';
};

/* ******************************搜索栏属性/方法****************************** */
// 搜索值
const searchProductValue = ref('');
// 搜索事件
const searchProductEvent = () => {
    if (searchProductValue.value == '') {
        // 原始数据
        data.length = 0;
        dataCache.forEach((item) => {
            data.push(item);
        });
    } else {
        // 筛选数据
        data.length = 0;
        dataCache.forEach((item) => {
            if (
                item.productName.includes(searchProductValue.value) ||
                item.productSize.includes(searchProductValue.value) ||
                item.tissueSize.includes(searchProductValue.value) ||
                item.corrugatedSize.includes(searchProductValue.value) ||
                item.materialQuality.includes(searchProductValue.value)
            ) {
                data.push(item);
            }
        });
    }
};
// 输入框清空事件
const inputClearEvent = () => {
    // 原始数据
    data.length = 0;
    dataCache.forEach((item) => {
        data.push(item);
    });
};

/* ******************************产品打印属性/方法****************************** */
// 打印生产单dialog开关
const printVisible = ref(false);
// 打印生产单数据
const printData = reactive<any>([]);
// 打印事件
const printProduction = () => {
    // 如果没有勾选
    if (selected.length == 0) {
        ElMessage({
            message: '请勾选要打印的产品',
            type: 'warning',
            grouping: true,
        });
        return;
    }

    // 清空数据
    printData.length = 0;

    // 填充数据
    selected.forEach((item) => {
        // 找到对应的产品
        const product = data.find((product) => product._id == item);
        // 填充数据
        printData.push(product!);
    });

    // 打印
    printVisible.value = true;
};

// 打印产品标识dialog开关
const printProductSymbolVisible = ref(false);
// 打印产品标识的数据
const printProductSymbolData = ref({
    customerAbbreviation: '',
    productName: '',
    productSize: '',
    productionNumber: 0,
});
const printProductSymbol = () => {
    // 如果没有勾选
    if (selected.length == 0) {
        ElMessage({
            message: '请勾选要打印的产品',
            type: 'warning',
            grouping: true,
        });
        return;
    }

    printProductSymbolData.value.customerAbbreviation = customerInfo.value.customerAbbreviation;
    // 填充数据
    selected.forEach((item) => {
        // 找到对应的产品
        const product = data.find((product) => product._id == item);
        // 填充数据
        printProductSymbolData.value.productName = product!.productName;
        printProductSymbolData.value.productSize = product!.productSize;
    });

    printProductSymbolVisible.value = true;
};

/* ******************************添加产品属性/方法****************************** */
// 添加产品表单dialog开关
const addProductVisible = ref(false);
// 表单实例
const productFormRef = ref();
// 表单数据
const addProductForm = reactive<AjaxRequest['productForm']['product']>({
    priority: 1,
    boxType: '包装箱',
    materialNumber: '',
    productName: '',
    productSize: '',
    productSpecification: '',
    design: [],
    tissueSize: '',
    corrugatedSize: '',
    materialQuality: '',
    crimping: '',
    spell: 1,
    process: '',
    excludTaxPrice: 0,
    includeTaxPrice: 0,
    history: [],
    collocation: [],
    description: '',
    creator: useUserStore().username,
    creatorId: useUserStore().id,
});
// 包装类型
const options: { value: string; label: string; disabled: boolean }[] = [
    { value: '包装盒', label: '包装盒', disabled: false },
    { value: '包装箱', label: '包装箱', disabled: false },
    { value: '内衬', label: '内衬', disabled: false },
    { value: '垫板/隔板', label: '垫板/隔板', disabled: false },
    { value: '隔条', label: '隔条', disabled: false },
    { value: '不干胶', label: '不干胶', disabled: false },
    { value: '绳/提手', label: '绳/提手', disabled: false },
    { value: '珍珠棉', label: '珍珠棉', disabled: false },
    { value: '其他', label: '其他', disabled: false },
];
// 粘口
const glueSize = ref(30);
// 自定义验证产品名称重复
const checkProductNameRepeat = (_rule: any, value: any, callback: any) => {
    if (!value) {
        return callback(new Error('产品名称不能为空'));
    }
    // 异步验证名称是否能用
    checkProductName(customerInfo.value.customerId, value).then((res: any) => {
        if (res.data) {
            callback(new Error('产品名称已存在'));
        } else {
            // 去除一些歧义字符串
            const reg1 = new RegExp(/‘/, 'ig');
            const reg2 = new RegExp(/“/, 'ig');
            const reg3 = new RegExp(/’/, 'ig');
            const reg4 = new RegExp(/”/, 'ig');
            addProductForm.productName = value.replace(reg1, "'").replace(reg2, '"').replace(reg3, "'").replace(reg4, '"');
            callback();
        }
    });
};
// 自定义验证产品尺寸
const checkProductSize = (_rule: any, value: any, callback: any) => {
    if (!value) {
        callback();
    }
    const productSizeReg1 = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}[*][0-9]{0,4}$/);
    const productSizeReg2 = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}$/);
    if (productSizeReg1.test(value)) {
        callback();
    } else if (productSizeReg2.test(value)) {
        callback();
    } else {
        return callback(new Error('产品尺寸格式不正确'));
    }
};
// 自定义验证产品面纸/瓦纸规格
const checkProductTissueOrCorrugatedSize = (_rule: any, value: any, callback: any) => {
    if (!value) {
        callback();
    }
    const productSizeReg = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}$/);
    if (productSizeReg.test(value)) {
        callback();
    } else {
        return callback(new Error('产品格式不正确'));
    }
};
// 自定义验证产品拼数
const checkProductSpell = (_rule: any, value: any, callback: any) => {
    if (!value) {
        return callback(new Error('拼数不能为空'));
    }

    const spell = Number(value);
    if (spell <= 0) {
        return callback(new Error('请填入大于0的数'));
    }

    callback();
};
// 自定义验证产品价格
const checkProductPrice = (_rule: any, value: any, callback: any) => {
    const price = Number(Number(value).toFixed(2));
    if (typeof price !== 'number' || price !== price) {
        return callback(new Error('请填入数字'));
    }

    callback();
};
// 价格输入框失去焦点事件
const blurPriceEvent = (type: string) => {
    // 如果是不含税价格
    if (type == 'excludTaxPrice') {
        const price = Number(Number(addProductForm.excludTaxPrice).toFixed(2));
        if (typeof price !== 'number' || price !== price) {
            addProductForm.excludTaxPrice = 0;
            addProductForm.includeTaxPrice = 0;
        } else {
            addProductForm.excludTaxPrice = price;
            addProductForm.includeTaxPrice = Number((price * 1.13).toFixed(2));
        }
    } else {
        const price = Number(Number(addProductForm.includeTaxPrice).toFixed(2));
        if (typeof price !== 'number' || price !== price) {
            addProductForm.excludTaxPrice = 0;
            addProductForm.includeTaxPrice = 0;
        } else {
            addProductForm.includeTaxPrice = price;
            addProductForm.excludTaxPrice = Number((price / 1.13).toFixed(2));
        }
    }
};
// 表单校验规则
const rules = reactive<FormRules<typeof addProductForm>>({
    boxType: [{ required: true, message: '请选择包装类型', trigger: 'blur' }],
    productName: [
        { validator: checkProductNameRepeat, trigger: 'blur' },
        {
            required: true,
            message: '产品名称不能为空',
        },
    ],
    productSize: [{ validator: checkProductSize, trigger: 'blur' }],
    tissueSize: [{ validator: checkProductTissueOrCorrugatedSize, trigger: 'blur' }],
    corrugatedSize: [{ validator: checkProductTissueOrCorrugatedSize, trigger: 'blur' }],
    materialQuality: [{ required: true, message: '请输入材质', trigger: 'blur' }],
    spell: [
        { validator: checkProductSpell, trigger: 'blur' },
        { required: true, message: '拼数不能为空', trigger: 'change' },
    ],
    process: [{ required: true, message: '请输入工艺', trigger: 'blur' }],
    excludTaxPrice: [
        { validator: checkProductPrice, trigger: 'blur' },
        { required: true, message: '价格不能为空', trigger: 'change' },
    ],
    includeTaxPrice: [
        { validator: checkProductPrice, trigger: 'blur' },
        { required: true, message: '价格不能为空', trigger: 'change' },
    ],
});
// 粘口变动事件
const changeGlueSizeEvent = () => {
    addProductForm.corrugatedSize = '';
    addProductForm.crimping = '';
};
// 计算三层外箱的尺寸
const calculateThreeLayersOuterBoxSize = () => {
    if (addProductForm.productSize == '') {
        return;
    } else {
        const productSizeReg = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}[*][0-9]{0,4}$/);
        if (productSizeReg.test(addProductForm.productSize)) {
            const productSize = addProductForm.productSize.split('*');
            const length = Number(productSize[0]);
            const width = Number(productSize[1]);
            const height = Number(productSize[2]);
            // 仅用于常规 三层板 包装箱产品，粘口默认30mm，折痕默认2mm。
            addProductForm.corrugatedSize = `${(length + width) * 2 + Number(glueSize.value)}*${width + height + 2}`;
            addProductForm.crimping = `${width / 2 + 1}*${height}*${width / 2 + 1}`;
        }
    }
};
// 计算五层外箱的尺寸
const calculateFiveLayersOuterBoxSize = () => {
    if (addProductForm.productSize == '') {
        return;
    } else {
        const productSizeReg = new RegExp(/^[0-9]{0,4}[*][0-9]{0,4}[*][0-9]{0,4}$/);
        if (productSizeReg.test(addProductForm.productSize)) {
            const productSize = addProductForm.productSize.split('*');
            const length = Number(productSize[0]);
            const width = Number(productSize[1]);
            const height = Number(productSize[2]);
            // 仅用于常规 五层板包装箱产品，粘口默认30mm，折痕默认4mm。
            addProductForm.corrugatedSize = `${(length + width) * 2 + Number(glueSize.value)}*${width + height + 4}`;
            addProductForm.crimping = `${width / 2 + 2}*${height}*${width / 2 + 2}`;
        }
    }
};
// 表单提交事件
const addProductSubmitEvent = () => {
    productFormRef.value.validate((valid: boolean) => {
        if (valid) {
            // 赋值编号
            addProductForm.priority = data.length + 1;
            // 最终校验
            createProduct({
                customerName: customerInfo.value.customerName,
                customerId: customerInfo.value.customerId,
                product: addProductForm,
            }).then((res) => {
                // 刷新列表
                updateForm(res.message);
                addProductForm.productName = '';
                addProductVisible.value = false;
            });
        } else {
            return false;
        }
    });
};
// 重置表单事件
const resetAddProductFormEvent = () => {
    productFormRef.value.resetFields();
};

/* ******************************切换产品属性/方法****************************** */
const changeProductList = (_state: typeof state.value) => {
    state.value = _state;
    switch (_state) {
        case true:
            updateForm('已切换为可用产品');
            break;
        case false:
            updateForm('已切换为不可用产品');
            break;
    }
};

/* ******************************排序属性/方法****************************** */
// 重新排序产品
const reorderProductPriorityEvent = () => {
    reorderProductPriority(customerInfo.value.customerId).then(() => {
        updateForm('排序成功');
    });
};

/* ******************************导入产品属性/方法****************************** */
// 上传实例
const upload = ref<UploadInstance>();
// 上传文件
const handleFileChange = (uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    if (uploadFile.name.includes('.xlsx')) {
        // 读取excel文件
        const reader = new FileReader();
        reader.readAsArrayBuffer(uploadFile.raw as File);

        // 当读取完成时
        reader.onload = () => {
            // 需要上传的数据
            const _data: any[] = [];

            /* 解析工作簿 */
            const workbook = read(reader.result);

            /* 获取第一个工作表 */
            const worksheet = workbook.Sheets[workbook.SheetNames[0]];
            const raw_data = utils.sheet_to_json(worksheet, { header: 1 });

            try {
                /* 解析数据 */
                for (let index = 1; index < raw_data.length; index++) {
                    const raw = raw_data[index] as any;
                    // 去空
                    if (raw.length !== 0) {
                        _data.push({
                            priority: raw[1] || index,
                            boxType: raw[2] || '其他',
                            materialNumber: raw[3] || '',
                            productName: raw[4] || '',
                            productSize: raw[5] || '',
                            productSpecification: raw[6] || '',
                            design: raw[7] || [],
                            stock: raw[8] || 0,
                            tissueSize: raw[9] || '',
                            corrugatedSize: raw[10] || '',
                            materialQuality: raw[11] || '',
                            crimping: raw[12] || '',
                            spell: Number(raw[13]) || 1,
                            process: raw[14] || '',
                            excludTaxPrice: Number(Number(raw[15]).toFixed(2)) || 0,
                            includeTaxPrice: Number(Number(raw[16]).toFixed(2)) || 0,
                            history: raw[17] || [],
                            collocation: raw[18] || [],
                            description: raw[19] || '',
                        });
                    }
                }
            } catch (error) {
                ElMessage.error('数据验证失败，请重新填写。');
            }

            // 导入数据库
            if (checkData(_data)) importProductEvent(_data);
        };
    } else {
        // 读取json文件
        const reader = new FileReader();
        // @ts-ignore
        reader.readAsText(uploadFile.raw);
        // 当读取完成时
        reader.onload = () => {
            // @ts-ignore
            const data = JSON.parse(reader.result);
            // 检查数据的合法性并加工数据
            if (checkData(data)) {
                importProductEvent(data);
            }
        };
    }
};
// 上传文件超出限制覆盖前一个文件
const handleExceed: UploadProps['onExceed'] = (files) => {
    upload.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    upload.value!.handleStart(file);
};
// 检查数据的合法性
const checkData = (_data: any): Boolean => {
    // 检测数据类型
    if (typeof _data !== 'object') {
        ElMessage.error('导入的数据无法识别');
        return false;
    }

    // 检测数据长度
    if (_data.length === 0) {
        ElMessage.error('数据为空无法导入');
        return false;
    }

    // 检测产品名称数据是否重复
    const productName = new Map();

    // 检测导入数据
    for (let index = 0; index < _data.length; index++) {
        const element = _data[index];
        let count = 0;
        // 检测每个数据字段
        for (const key in element) {
            if (Object.prototype.hasOwnProperty.call(element, key)) {
                // 检测字段是否存在
                if (
                    key == 'priority' ||
                    key == 'boxType' ||
                    key == 'materialNumber' ||
                    key == 'productName' ||
                    key == 'productSize' ||
                    key == 'productSpecification' ||
                    key == 'design' ||
                    key == 'stock' ||
                    key == 'tissueSize' ||
                    key == 'corrugatedSize' ||
                    key == 'materialQuality' ||
                    key == 'crimping' ||
                    key == 'spell' ||
                    key == 'process' ||
                    key == 'excludTaxPrice' ||
                    key == 'includeTaxPrice' ||
                    key == 'history' ||
                    key == 'collocation' ||
                    key == 'description'
                ) {
                    count++;
                }
            }
        }

        if (count !== 19) {
            ElMessage.error('数据格式不正确');
            return false;
        }

        productName.set(String(element.productName), index);
    }

    console.log(productName);

    // 检测已有数据
    for (let index = 0; index < data.length; index++) {
        const element = data[index];
        if (productName.get(String(element.productName)) !== undefined) {
            ElMessage.error('导入文件中产品名称有重复项');
            return false;
        }
    }

    if (productName.size !== _data.length) {
        ElMessage.error('导入文件中产品名称有重复项');
        return false;
    }

    return true;
};
// 文件导入产品事件
const importProductEvent = (data) => {
    const _data = data.map((item) => {
        // 最后再次处理价格
        if (item.excludTaxPrice !== 0) {
            item.includeTaxPrice = Number(Decimal.div(Number(item.excludTaxPrice), 1.13).toFixed(2));
        }
        if (item.includeTaxPrice !== 0) {
            item.excludTaxPrice = Number(Decimal.div(Number(item.includeTaxPrice), 1.13).toFixed(2));
        }
        return {
            ...item,
            creator: useUserStore().username,
            creatorId: useUserStore().id,
        };
    });
    importProduct(customerInfo.value.customerId, _data).then(() => {
        updateForm('导入成功');
    });
};

/* ******************************导出产品属性/方法****************************** */
// 导出json格式产品列表事件
const exportProductJsonEvent = () => {
    if (data.length == 0) {
        ElMessage({
            message: '暂无数据可导出',
            type: 'warning',
            grouping: true,
        });
    } else {
        // 加工导出的数据
        const _data: any[] = [];
        getProductList(customerInfo.value.customerId).then((res) => {
            res.data.forEach((item: any) => {
                delete item.productAvailable;
                delete item.creator;
                delete item.creatorId;
                delete item._id;
                _data.push(item);
            });
            // 创建一个a标签
            let a: HTMLAnchorElement | null = document.createElement('a');
            // json化导出数据并把地址挂载到a标签上
            a.href = URL.createObjectURL(new Blob([JSON.stringify(_data)]));
            // 设置下载文件名
            a.download = dayjs().format('YYYY-MM-DD_HH-mm-ss@') + 'product.json';
            // 模拟下载
            a.click();
            // 释放内存
            a = null;
        });
    }
};
// 导出xlsx格式产品列表事件
const exportProductXlsxEvent = () => {
    if (data.length == 0) {
        ElMessage({
            message: '暂无数据可导出',
            type: 'warning',
            grouping: true,
        });
    } else {
        // 加工导出的数据
        const _data: any[] = [];
        getProductList(customerInfo.value.customerId).then((res) => {
            // 需要导出的数据
            res.data.forEach((item: any) => {
                delete item.productAvailable;
                delete item.creator;
                delete item.creatorId;
                delete item._id;
                _data.push(item);
            });

            // 生成工作簿和工作表
            const worksheet = utils.json_to_sheet(_data);
            const workbook = utils.book_new();
            utils.book_append_sheet(workbook, worksheet, '客户列表');

            // 创建标头
            utils.sheet_add_aoa(
                worksheet,
                [
                    [
                        '编号',
                        '包装类型',
                        '物料号',
                        '产品名称',
                        '产品尺寸',
                        '产品规格',
                        '面纸规格',
                        '瓦楞规格',
                        '材质',
                        '压线',
                        '拼数',
                        '工艺',
                        '库存',
                        '不含税价',
                        '含税价',
                        '图稿',
                        '记录',
                        '搭配',
                        '描述',
                    ],
                ],
                { origin: 'A1' }
            );

            writeFile(workbook, `${dayjs().format('YYYY-MM-DD_HH-mm-ss@')}${customerInfo.value.customerName}产品库.xlsx`, { compression: true });
        });
    }
};

/* ******************************下载产品模板的属性/方法****************************** */
// 下载客户导入模板的事件
const downloadProductTemplateEvent = () => {
    downloadProductTemplate().then((res: any) => {
        // 下载数据地址挂载到a标签上
        let a: HTMLAnchorElement | null = document.createElement('a');
        const url = URL.createObjectURL(res);
        // 创建一个URL表示Blob对象
        a.href = url;
        // 设置下载文件名
        a.download = '导入产品列表模板.xlsx';
        // 模拟下载
        a.click();
        // 释放内存
        // 释放内存
        URL.revokeObjectURL(url);
    });
};

/* ******************************恢复产品属性/方法****************************** */
const recoverProductEvent = () => {
    if (selected.length == 0) {
        ElMessage({
            message: '请选择要恢复的产品',
            type: 'warning',
            grouping: true,
        });
    } else {
        recoverProduct(customerInfo.value.customerId, selected).then(() => {
            updateForm('恢复成功');
        });
    }
};

/* ******************************删除产品属性/方法****************************** */
const deleteProductEvent = () => {
    if (selected.length == 0) {
        ElMessage({
            message: '请选择要删除的产品',
            type: 'warning',
            grouping: true,
        });
    } else {
        deleteProduct(customerInfo.value.customerId, customerInfo.value.customerName, selected).then(() => {
            updateForm('删除成功');
        });
    }
};

/* ******************************彻底删除产品属性/方法****************************** */
const deleteProductCompletelyEvent = () => {
    if (selected.length == 0) {
        ElMessage({
            message: '请选择要彻底删除的产品',
            type: 'warning',
            grouping: true,
        });
    } else {
        deleteProductCompletely(customerInfo.value.customerId, customerInfo.value.customerName, selected).then(() => {
            updateForm('彻底删除成功');
        });
    }
};

/* ******************************上传产品缩略图dialog属性/方法****************************** */
// 显示产品缩略图上传对话框
const uploadProductThumbnailDialogVisible = ref(false);
// 产品缩略图的名称
const uploadProductThumbnailName = ref('');
// 产品缩略图的id
const uploadProductThumbnailId = ref('');
// 产品缩略图上传地址
const thumbnailAction = ref(import.meta.env.VITE_APP_UPLOAD_URL + import.meta.env.VITE_APP_BASE_API + HttpUrl.uploadProductThumbnail);
// 产品缩略图上传组件实例
const uploadProductThumbnailRef = ref<UploadInstance>();
// 产品缩略图的尺寸地址
const imageSizeSrc = ref('');
// 产品的碎略图
const imageSize = ref({
    width: 0,
    height: 0,
});
// 产品缩略图文件发生变化时触发
const handleProductThumbnailChangeEvent = (uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    // 计算图片的尺寸
    imageSizeSrc.value = URL.createObjectURL(uploadFile.raw as File);

    // 验证文件大小
    if (bytesToMB(uploadFile.size as number) >= 2) {
        ElMessage({
            message: '图片大小不能超过2MB',
            type: 'warning',
            grouping: true,
        });
        uploadProductThumbnailRef.value!.clearFiles();
    }

    // 验证文件类型
    if (
        !(
            uploadFile.raw?.type == 'image/jpeg' ||
            uploadFile.raw?.type == 'image/png' ||
            uploadFile.raw?.type == 'image/webp' ||
            uploadFile.raw?.type == 'image/jpeg'
        )
    ) {
        ElMessage({
            message: '不支持的文件类型',
            type: 'warning',
            grouping: true,
        });
        uploadProductThumbnailRef.value!.clearFiles();
    }
};
// 图片加载完毕，记录图片尺寸
const onImageLoad = (event: any) => {
    imageSize.value.width = Number(event.target.width);
    imageSize.value.height = Number(event.target.height);
};
// 覆盖前一个产品缩略图
const handleProductThumbnailExceedEvent: UploadProps['onExceed'] = (files) => {
    uploadProductThumbnailRef.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    uploadProductThumbnailRef.value!.handleStart(file);
};
// 产品缩略图手动上传
const productThumbnailSubmitEvent = () => {
    if (imageSize.value.width >= imageSize.value.height) {
        uploadProductThumbnailRef.value!.submit();
    } else {
        ElMessage({
            message: '图片宽高比不正确，请重新上传',
            type: 'warning',
            grouping: true,
        });
    }
};
// 产品缩略图上传时的回调
const uploadProductThumbnailProgressEvent = (evt: UploadProgressEvent, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    console.log(evt);
};
// 产品缩略图成功上传的回调
const uploadProductThumbnailSuccessEvent = (response: any, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    ElMessage({
        message: response.message,
        type: 'success',
        grouping: true,
    });
    uploadProductThumbnailDialogVisible.value = false;
    updateForm();
};
// 产品缩略图上传失败的回调
const uploadProductThumbnailErrorEvent = (_err: Error, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    ElMessage({
        message: '上传失败',
        type: 'error',
        grouping: true,
    });
};

/* ******************************列表展示产品图稿dialog属性/方法****************************** */
// 显示产品图稿列表对话框
const showProductDesignDialogVisible = ref(false);
// 产品图稿的名称
const showProductDesignName = ref('');
// 产品图稿的id
const showProductDesignId = ref('');
// 产品印刷图稿上传地址
const designAction = ref(import.meta.env.VITE_APP_UPLOAD_URL + import.meta.env.VITE_APP_BASE_API + HttpUrl.uploadProductDesign);
// 产品图稿上传组件实例
const uploadProductDesignRef = ref<UploadInstance>();
// 覆盖前一个产品图稿
const handleProductDesignExceedEvent: UploadProps['onExceed'] = (files) => {
    uploadProductDesignRef.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    uploadProductDesignRef.value!.handleStart(file);
};
// 产品图稿上传时的回调
const uploadProductDesignProgressEvent = (evt: UploadProgressEvent, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    console.log(evt);
};
// 产品图稿成功上传的回调
const uploadProductDesignSuccessEvent = (response: any, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    ElMessage({
        message: response.message,
        type: 'success',
        grouping: true,
    });
    updateForm();
};
// 产品图稿上传失败的回调
const uploadProductDesignErrorEvent = (_err: Error, _uploadFile: UploadFile, _uploadFiles: UploadFiles) => {
    ElMessage({
        message: '上传失败',
        type: 'error',
        grouping: true,
    });
};
// 下载产品图稿
const downloadProductDesignEvent = async (src: string) => {
    if (src == '') {
        ElNotification({
            title: '系统提示',
            type: 'warning',
            message: '没有图稿可供下载',
        });
    } else {
        // 文件名
        const res = await downloadProductDesign(src);

        if (!res) {
            ElNotification({
                title: '系统提示',
                type: 'warning',
                message: '文件不存在或被移动在其他目录',
            });
            return;
        }

        ElMessage({
            message: '该下载任务后台处理中，请稍后...',
        });

        // 下载数据地址挂载到a标签上
        let a: HTMLAnchorElement | null = document.createElement('a');
        // 创建一个URL表示Blob对象
        const url = URL.createObjectURL(res as unknown as Blob);
        // 创建一个URL表示Blob对象
        a.href = url;
        // 设置下载文件名
        a.download = `${src.split('/')[src.split('/').length - 1]}`;
        // 模拟下载
        a.click();
        // 释放内存
        URL.revokeObjectURL(url);
    }
};
// 删除产品图稿
const deleteProductDesignEvent = (type: 'all' | 'designFile' | 'thumbnail', productDesignIndex: number) => {
    // 定位到产品
    const product = data.find((item) => item._id === showProductDesignId.value);
    if (!product) {
        ElMessage({
            message: '该产品不存在',
            type: 'error',
            grouping: true,
        });
        return;
    }

    if (type === 'designFile') {
        if (product?.design[productDesignIndex].designFile == '') {
            ElMessage({
                message: '该产品不满足图稿删除条件',
                type: 'warning',
                grouping: true,
            });
            return;
        }
    }
    if (type === 'thumbnail') {
        if (product?.design[productDesignIndex].thumbnail == '') {
            ElMessage({
                message: '该产品不满足缩略图删除条件',
                type: 'warning',
                grouping: true,
            });
            return;
        }
    }

    deleteProductDesign(
        type,
        customerInfo.value.customerId,
        customerInfo.value.customerName,
        showProductDesignId.value,
        productDesignIndex,
        showProductDesignName.value
    ).then(() => {
        ElMessage({
            message: '删除成功',
            type: 'success',
            grouping: true,
        });
        updateForm();
    });
};
</script>

<style>
.sfc-el-button + .sfc-el-button {
    margin-left: 0px !important;
}
</style>
